package com.ssy.lingxi.settle.accounts.serviceimpl;

import com.ssy.lingxi.common.constant.settle.SettlementTypeEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.dto.request.MemberSettlementStrategyRequest;
import com.ssy.lingxi.dto.response.MemberSettlementStrategyResponse;
import com.ssy.lingxi.settle.accounts.entity.MemberSettlementStrategyDO;
import com.ssy.lingxi.settle.accounts.entity.MemberSettlementStrategyMemberDO;
import com.ssy.lingxi.common.constant.settle.SettlementOrderTypeEnum;
import com.ssy.lingxi.settle.accounts.model.constant.SettlementStrategyStatusEnum;
import com.ssy.lingxi.settle.accounts.model.constant.SettlementWayEnum;
import com.ssy.lingxi.settle.accounts.model.vo.request.*;
import com.ssy.lingxi.settle.accounts.model.vo.response.MemberSettlementStrategyDetailVO;
import com.ssy.lingxi.settle.accounts.model.vo.response.MemberSettlementStrategyMemberVO;
import com.ssy.lingxi.settle.accounts.model.vo.response.MemberSettlementStrategyVO;
import com.ssy.lingxi.settle.accounts.repository.MemberSettlementStrategyMemberRepository;
import com.ssy.lingxi.settle.accounts.repository.MemberSettlementStrategyRepository;
import com.ssy.lingxi.settle.accounts.service.IMemberSettlementStrategyService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 会员结算策略接口实现
 * @author 伍将
 * @date 2020/10/21
 * @version 2.0.0
 */
@Service
public class MemberSettlementStrategyServiceImpl implements IMemberSettlementStrategyService {

    @Resource
    private MemberSettlementStrategyRepository repository;

    @Resource
    private MemberSettlementStrategyMemberRepository memberRepository;


    /**
     * 分页查询会员结算策略
     * @author 伍将
     * @date 2020/10/21
     * @param sysUser:
     * @param pageVO:
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.common.response.PageData < com.ssy.lingxi.settle.accounts.mode.vo.response.MemberSettlementStrategyVO>>
     **/
    @Override
    public Wrapper<PageData<MemberSettlementStrategyVO>> pageStrategy(UserLoginCacheDTO sysUser, MemberSettlementStrategyPageVO pageVO) {

        // step 1: 组装查询条件
        Specification<MemberSettlementStrategyDO> spec =  (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("memberId").as(Long.class), sysUser.getMemberId()));
            list.add(criteriaBuilder.equal(root.get("roleId").as(Long.class), sysUser.getMemberRoleId()));
            if (StringUtils.hasLength(pageVO.getName())) {
                list.add(criteriaBuilder.like(root.get("name").as(String.class), "%" + pageVO.getName().trim() + "%"));
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        // step 2: 组装分页参数
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("status").descending());

        // step 3: 分页查询数据
        Page<MemberSettlementStrategyDO> result = repository.findAll(spec, page);

        // step 4: 组装数据
        List<MemberSettlementStrategyVO> resultList = result.getContent().stream().map(r -> {
            MemberSettlementStrategyVO queryVO = new MemberSettlementStrategyVO();
            queryVO.setId(r.getId());
            queryVO.setName(r.getName());
            queryVO.setSettlementWayName(SettlementWayEnum.getMessage(r.getSettlementWay()));
            queryVO.setSettlementOrderTypeName(SettlementOrderTypeEnum.getMessage(r.getSettlementOrderType(),""));
            queryVO.setStatus(r.getStatus());
            queryVO.setStatusName(SettlementStrategyStatusEnum.getMessage(r.getStatus()));
            queryVO.setSettlementPaymentTypeName(SettlementTypeEnum.getName(r.getSettlementPaymentType()));
            return queryVO;
        }).collect(Collectors.toList());

        return Wrapper.success(new PageData<>(result.getTotalElements(), resultList));
    }

    /**
     * 设置会员结算策略状态
     * @author 伍将
     * @date 2020/10/21
     * @param sysUser: 
     * @param setStatusVO: 
     * @return com.ssy.lingxi.common.response.Wrapper
     **/
    @Transactional
    @Override
    public Wrapper<Void> setStatus(UserLoginCacheDTO sysUser, MemberSettlementStrategySetStatusVO setStatusVO) {

        MemberSettlementStrategyDO entity = repository.findById(setStatusVO.getId()).orElse(null);
        if (entity == null) {
            throw new BusinessException(ResponseCode.SA_MEMBER_SETTLEMENT_STRATEGY_NOT_EXIST);
        }

        entity.setStatus(setStatusVO.getStatus());
        entity.setUpdateTime(System.currentTimeMillis());
        repository.saveAndFlush(entity);

        // 当设置策略为有效时需要验证下属成员是否存在多个有效策略中
        if (entity.getStatus().equals(SettlementStrategyStatusEnum.VALID.getCode())) {
            Boolean isExists = existsStrategy(entity);
            if (isExists) {
                throw new BusinessException(ResponseCode.SA_MEMBER_SETTLEMENT_STRATEGY_MEMBER_USED);
            }
        }

        return Wrapper.success();
    }

    /**
     * 查询会员结算策略详情
     * @author 伍将
     * @date 2020/10/21
     * @param id: 
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.settle.accounts.mode.vo.response.MemberSettlementStrategyDetailVO>
     **/
    @Override
    public Wrapper<MemberSettlementStrategyDetailVO> getDetail(Long id) {
        MemberSettlementStrategyDO entity = repository.findById(id).orElse(null);
        if (entity == null) {
            throw new BusinessException(ResponseCode.SA_MEMBER_SETTLEMENT_STRATEGY_NOT_EXIST);
        }

        MemberSettlementStrategyDetailVO result = new MemberSettlementStrategyDetailVO();
        result.setId(entity.getId());
        result.setName(entity.getName());
        result.setSettlementDate(entity.getSettlementDate());
        result.setSettlementDays(entity.getSettlementDays());
        result.setEstimatedPaymentDate(entity.getEstimatedPaymentDate());
        result.setSettlementOrderType(entity.getSettlementOrderType());
        result.setSettlementWay(entity.getSettlementWay());
        result.setStatus(entity.getStatus());
        result.setSettlementPaymentType(entity.getSettlementPaymentType());
        result.setSettlementPaymentTypeName(SettlementTypeEnum.getName(entity.getSettlementPaymentType()));

        List<MemberSettlementStrategyMemberDO> memberDOList = entity.getMemberList();
        if (memberDOList != null && memberDOList.size() > 0) {

            List<MemberSettlementStrategyMemberVO> memberList = memberDOList.stream().map(r -> {
                MemberSettlementStrategyMemberVO queryVO = new MemberSettlementStrategyMemberVO();
                queryVO.setMemberId(r.getMemberId());
                queryVO.setRoleId(r.getRoleId());
                queryVO.setMemberName(r.getMemberName());
                queryVO.setRoleName(r.getRoleName());
                queryVO.setMemberTypeName(r.getMemberTypeName());
                queryVO.setLevelName(r.getLevelName());

                return queryVO;
            }).collect(Collectors.toList());

            result.setMemberList(memberList);
        }


        return Wrapper.success(result);
    }

    /**
     * 新增会员结算策略
     * @author 伍将
     * @date 2020/10/21
     * @param addVO: 
     * @return com.ssy.lingxi.common.response.Wrapper<java.lang.Long>
     **/
    @Transactional
    @Override
    public Wrapper<Long> add(UserLoginCacheDTO sysUser, MemberSettlementStrategyAddVO addVO) {

        MemberSettlementStrategyDO entity = new MemberSettlementStrategyDO();
        entity.setMemberId(sysUser.getMemberId());
        entity.setRoleId(sysUser.getMemberRoleId());
        entity.setName(addVO.getName());
        entity.setSettlementWay(addVO.getSettlementWay());
        entity.setSettlementDate(addVO.getSettlementDate());
        entity.setSettlementDays(addVO.getSettlementDays());
        entity.setEstimatedPaymentDate(addVO.getEstimatedPaymentDate());
        entity.setSettlementOrderType(addVO.getSettlementOrderType());
        entity.setSettlementPaymentType(addVO.getSettlementPaymentType()); // 添加结算支付方式
        entity.setStatus(SettlementStrategyStatusEnum.VALID.getCode()); // 默认为有效
        entity.setCreateTime(System.currentTimeMillis());
        entity.setUpdateTime(0L);


        // 保存策略下会员
        if (addVO.getMemberList() != null && addVO.getMemberList().size() > 0) {
            List<MemberSettlementStrategyMemberDO> memberList = addVO.getMemberList().stream().distinct().map(r -> {
                MemberSettlementStrategyMemberDO member = new MemberSettlementStrategyMemberDO();
                member.setMemberId(r.getMemberId());
                member.setRoleId(r.getRoleId());
                member.setMemberName(r.getMemberName());
                member.setRoleName(r.getRoleName());
                member.setMemberTypeName(r.getMemberTypeName());
                member.setLevelName(r.getLevelName());
                member.setStrategy(entity);
                return member;
            }).collect(Collectors.toList());

            entity.setMemberList(memberList);
        }

        repository.saveAndFlush(entity);

        // 当结算策略为有效时，验证策略下会员是否拥有多个结算策略
        if (entity.getStatus().equals(SettlementStrategyStatusEnum.VALID.getCode())) {
            Boolean isExists = existsStrategy(entity);
            if (isExists) {
                throw new BusinessException(ResponseCode.SA_MEMBER_SETTLEMENT_STRATEGY_MEMBER_USED);
            }
        }

        return Wrapper.success(entity.getId());
    }

    /**
     * 更新会员结算策略
     * @author 伍将
     * @date 2020/10/21
     * @param updateVO: 
     * @return com.ssy.lingxi.common.response.Wrapper<java.lang.Long>
     **/
    @Transactional
    @Override
    public Wrapper<Long> update(UserLoginCacheDTO sysUser, MemberSettlementStrategyUpdateVO updateVO) {

        MemberSettlementStrategyDO entity = repository.findById(updateVO.getId()).orElse(null);
        if (entity == null) {
            throw new BusinessException(ResponseCode.SA_MEMBER_SETTLEMENT_STRATEGY_NOT_EXIST);
        }

        entity.setName(updateVO.getName());
        entity.setSettlementWay(updateVO.getSettlementWay());
        entity.setSettlementDate(updateVO.getSettlementDate());
        entity.setSettlementDays(updateVO.getSettlementDays());
        entity.setEstimatedPaymentDate(updateVO.getEstimatedPaymentDate());
        entity.setSettlementOrderType(updateVO.getSettlementOrderType());
        entity.setUpdateTime(System.currentTimeMillis());
        // 修改结算支付方式
        entity.setSettlementPaymentType(updateVO.getSettlementPaymentType());
        repository.saveAndFlush(entity);

        // 删除原始策略下会员
        memberRepository.deleteByStrategyId(entity.getId());

        // 保存策略下会员
        if (updateVO.getMemberList() != null && updateVO.getMemberList().size() > 0) {

            List<MemberSettlementStrategyMemberDO> memberList = updateVO.getMemberList().stream().distinct().map(r -> {
                MemberSettlementStrategyMemberDO member = new MemberSettlementStrategyMemberDO();
                member.setMemberId(r.getMemberId());
                member.setRoleId(r.getRoleId());
                member.setMemberName(r.getMemberName());
                member.setRoleName(r.getRoleName());
                member.setMemberTypeName(r.getMemberTypeName());
                member.setLevelName(r.getLevelName());
                member.setStrategy(entity);
                return member;
            }).collect(Collectors.toList());
            entity.setMemberList(memberList);

            // 当结算策略为有效时，验证策略下会员是否拥有多个结算策略
            if (entity.getStatus().equals(SettlementStrategyStatusEnum.VALID.getCode())) {
                Boolean isExists = existsStrategy(entity);
                if (isExists) {
                    throw new BusinessException(ResponseCode.SA_MEMBER_SETTLEMENT_STRATEGY_MEMBER_USED);
                }
            }
        }

        return Wrapper.success();
    }

    /**
     * 检查结算策略是否存在
     * @author 伍将
     * @date 2020/10/22
     * @param strategyDO:
     * @return java.lang.Boolean
     **/
    private Boolean existsStrategy(MemberSettlementStrategyDO strategyDO) {

        boolean isExists = false;
        // 当前策略为有效时才验证
        if (strategyDO.getStatus().equals(SettlementStrategyStatusEnum.VALID.getCode())) {

            // 查询同类型单据数据
            List<MemberSettlementStrategyDO> strategyList = repository.findAllByMemberIdAndRoleIdAndStatusAndSettlementOrderType(strategyDO.getMemberId(), strategyDO.getRoleId(), strategyDO.getStatus(), strategyDO.getSettlementOrderType());

            List<String> tempList = strategyDO.getMemberList().stream().map(r -> r.getMemberId().toString() + r.getRoleId().toString()).collect(Collectors.toList());

            // 检查策略成员是否在多个策略中
            isExists = strategyList.stream().filter(
                    o -> !o.getId().equals(strategyDO.getId()))
                    .collect(Collectors.toList())
                    .stream().anyMatch(
                            o -> o.getMemberList().stream().anyMatch(
                                    item -> tempList.contains(item.getMemberId().toString() + item.getRoleId().toString())
                            )
                    );
        }

        return isExists;
    }

    /**
     * 获取物流结算方式
     * @param sysUser 用户
     * @return 物流结算方式
     */
    @Override
    public Wrapper<String> getLogisticsSettlementWay(UserLoginCacheDTO sysUser, SettlementWayGetVO getVO) {
        MemberSettlementStrategyRequest request=new MemberSettlementStrategyRequest();
        request.setMemberId(getVO.getMemberId().longValue());
        request.setRoleId(getVO.getRoleId().longValue());
        request.setSettlementOrderType(SettlementOrderTypeEnum.LOGISTICS.getCode());
        request.setSupplierMemberId(sysUser.getMemberId());
        request.setSupplierRoleId(sysUser.getMemberRoleId());
        MemberSettlementStrategyDO oneMemberSettlementStrategy = getOneMemberSettlementStrategy(request);
        String result="";
        if(oneMemberSettlementStrategy!=null){
            result=oneMemberSettlementStrategy.getName()+"("+SettlementWayEnum.getMessage(oneMemberSettlementStrategy.getSettlementWay(),oneMemberSettlementStrategy.getSettlementDays(),oneMemberSettlementStrategy.getSettlementDate())+")";
        }
        return Wrapper.success(result);
    }

    /**
     * 获取指定会员的结算方式
     * @return 会员的结算方式
     */
    private MemberSettlementStrategyDO getOneMemberSettlementStrategy(MemberSettlementStrategyRequest request) {
        Specification<MemberSettlementStrategyMemberDO> spec =  (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("memberId").as(Long.class), request.getMemberId()));
            list.add(criteriaBuilder.equal(root.get("roleId").as(Long.class), request.getRoleId()));
            list.add(criteriaBuilder.equal(root.get("strategy").get("status").as(Integer.class), SettlementStrategyStatusEnum.VALID.getCode()));
            list.add(criteriaBuilder.equal(root.get("strategy").get("settlementOrderType").as(Integer.class),request.getSettlementOrderType()));
            list.add(criteriaBuilder.equal(root.get("strategy").get("memberId").as(Integer.class), request.getSupplierMemberId()));
            list.add(criteriaBuilder.equal(root.get("strategy").get("roleId").as(Integer.class), request.getSupplierRoleId()));
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        MemberSettlementStrategyDO result=null;
        MemberSettlementStrategyMemberDO strategyMemberDO = memberRepository.findOne(spec).orElse(null);
        if (strategyMemberDO != null && strategyMemberDO.getStrategy() != null) {
            result = strategyMemberDO.getStrategy();
        }
        return result;
    }

    /**
     * 删除会员结算策略
     * @author 伍将
     * @date 2020/12/24
     * @param sysUser:
     * @param deleteVO:
     **/
    @Override
    public Wrapper<Void> delete(UserLoginCacheDTO sysUser, MemberSettlementStrategyDeleteVO deleteVO) {

        MemberSettlementStrategyDO entity = repository.findById(deleteVO.getId()).orElse(null);
        if (entity == null) {
            throw new BusinessException(ResponseCode.SA_MEMBER_SETTLEMENT_STRATEGY_NOT_EXIST);
        }
        if (entity.getStatus().equals(SettlementStrategyStatusEnum.VALID.getCode())) {
            throw new BusinessException(ResponseCode.SA_MEMBER_SETTLEMENT_STRATEGY_CAN_NOT_DELETE);
        }

        repository.delete(entity);

        return Wrapper.success();
    }

    /**
     * 获取会员有效的结算策略
     * @param memberSettlementStrategyRequest  会员结算策略请求
     * @return 会员有效的结算策略
     */
    @Override
    public Wrapper<MemberSettlementStrategyResponse> getMemberSettlementStrategy(MemberSettlementStrategyRequest memberSettlementStrategyRequest) {
        MemberSettlementStrategyDO memberSettlementStrategyDO = getOneMemberSettlementStrategy(memberSettlementStrategyRequest);
        MemberSettlementStrategyResponse response=null;
        if(memberSettlementStrategyDO!=null){
            response=new MemberSettlementStrategyResponse();
            response.setSettlementDate(memberSettlementStrategyDO.getSettlementDate());
            response.setSettlementDays(memberSettlementStrategyDO.getSettlementDays());
            response.setSettlementWay(memberSettlementStrategyDO.getSettlementWay());
        }
        return Wrapper.success(response);
    }
}
